package com.yeyks.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yeyks.dal.dao.AccountInfoMapper;
import com.yeyks.dal.domain.AccountInfo;
import com.yeyks.service.PayService;
import com.yeyks.util.Utility;
import com.yeyks.wxpay.WXPayConstants;
import com.yeyks.wxpay.WXPayUtil;
import com.yeyks.wxpay.impl.MyConfig;
import com.yeyks.wxpay.impl.WXPayUtility;
import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.yeyks.service.PayService;
import com.yeyks.util.Utility;
import com.yeyks.wxpay.WXPayConstants;
import com.yeyks.wxpay.WXPayUtil;
import com.yeyks.wxpay.impl.MyConfig;
import com.yeyks.wxpay.impl.WXPayUtility;
import jodd.util.StringUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.crypto.spec.SecretKeySpec;
import java.io.StringBufferInputStream;
import java.security.MessageDigest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class PayServiceImpl implements PayService {

    @Autowired
    private com.github.binarywang.wxpay.service.WxPayService payService;

    private boolean mockPay = false;

    public JSONObject wxParseCode(boolean h5orsapp, String code, MyConfig config) {
        JSONObject jsonObject = null;

        try {
            String response = null;
            if (h5orsapp) {
                String param = String.format(
                        "appid=%s&secret=%s&code=%s&grant_type=authorization_code",
                        config.getAppID(), config.getSecret(), code);

                response = Utility.sendGet("https://api.weixin.qq.com/sns/oauth2/access_token", param);
            } else {
                String param = String.format(
                        "appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                        config.getAppID(), config.getSecret(), code);

                response = Utility.sendGet("https://api.weixin.qq.com/sns/jscode2session", param);
            }
            jsonObject = (JSONObject) JSON.parse(response);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return jsonObject;
    }

    public JSONObject wxParseRefreshToken(String refreshToken) {
        JSONObject jsonObject = null;
        try {
            MyConfig config = new MyConfig();
            String param = String.format(
                    "appid=%s&grant_type=refresh_token&refresh_token=%s",
                    config.getAppID(),
                    refreshToken);

            String response = Utility.sendGet("https://api.weixin.qq.com/sns/oauth2/refresh_token", param);

            jsonObject = (JSONObject) JSON.parse(response);
        } catch (Throwable e) {
            e.printStackTrace();
        }

        return jsonObject;
    }


    public String wxCodeObject2RefreshToken(JSONObject jsonObject) {

        try {
            return jsonObject.get("refresh_token").toString();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    public String wxObject2OpenId(JSONObject jsonObject) {

        try {
            return jsonObject.get("openid").toString();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }


    public Map<String, String> genPayParam(
            String prepay_id) throws Exception {
        return genPayParam(prepay_id, WXPayConstants.SignType.MD5);
    }

    public static Map<String, String> genPayParam(
            String prepay_id, WXPayConstants.SignType signType) throws Exception {
        MyConfig config = new MyConfig();

        Map<String, String> data = new HashMap<String, String>();
        data.put("appId", config.getAppID());
        data.put("timeStamp", ((Long)(new Date().getTime() / 1000)).toString());
        data.put("nonceStr", WXPayUtil.generateNonceStr());
        data.put("package", "prepay_id=" + prepay_id);

        if (WXPayConstants.SignType.MD5.equals(signType)) {
            data.put("signType", WXPayConstants.MD5);
        }
        else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {
            data.put("signType", WXPayConstants.HMACSHA256);
        }
        data.put("paySign", WXPayUtil.generateSignature(data, config.getKey(), signType));

        return data;
    }

    public static String genTransParam(
            String openId, Integer amount, String spbill_create_ip,
            WXPayConstants.SignType signType) throws Exception {
        MyConfig config = new MyConfig();

        Map<String, String> data = new HashMap<String, String>();
        data.put("partner_trade_no", new Date().getTime() + "");
        data.put("openid", openId);
        data.put("check_name", "NO_CHECK");
        data.put("amount", amount.toString());
        data.put("desc", "提现");
        data.put("spbill_create_ip", spbill_create_ip);
        data.put("re_user_name", "bcn");

        data.put("mch_appid", config.getAppID());//公众账号ID
        data.put("mchid", config.getMchID());//商户号
        data.put("nonce_str", new Date().getTime() + Utility.randomString(7));//随机字符串

        if (WXPayConstants.SignType.MD5.equals(signType)) {
            data.put(WXPayConstants.FIELD_SIGN_TYPE, WXPayConstants.MD5);
        }
        else if (WXPayConstants.SignType.HMACSHA256.equals(signType)) {
            data.put(WXPayConstants.FIELD_SIGN_TYPE, WXPayConstants.HMACSHA256);
        }

        return WXPayUtil.generateSignatureParams(data, config.getKey(), signType);
    }

    @Override
    public Map<String, String> wxPreOrder(
            String openId, String body, Integer totalFee,
            String orderNo, String createIp, String notifyUrl) {
        return wxPreOrder(openId, body, totalFee, orderNo, createIp, notifyUrl, "JSAPI");
    }

    @Override
    public WxPayService getEngine() {
        return payService;
    }

    @Override
    public Map<String, String> wxPreOrder(
            String openId, String body, Integer totalFee,
            String orderNo, String createIp, String notifyUrl, String tradeType) {

        ////////////////////////////////////////////////////////////////////////
        //生成预支付订单
        WxPayUnifiedOrderRequest prepayInfo = WxPayUnifiedOrderRequest.newBuilder()
                .openid(openId)//公众号支付），此参数必传，此参数为微信用户在商户对应appid下的唯一标识
                .outTradeNo(orderNo)// 商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|* 且在同一个商户号下唯一
                .totalFee(totalFee)// 订单总金额，单位为分，详见支付金额
                .body(body)//商品描述
                //2、交易类型trade_type
                //JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付，统一下单接口trade_type的传参可参考这里
                //
                //MICROPAY--刷卡支付，刷卡支付有单独的支付接口，不调用统一下单接口
                .tradeType(tradeType)
                .spbillCreateIp(createIp)//用户终端ip
                .notifyUrl(notifyUrl)//异步接收微信支付结果通知的回调地址，通知url必须为外网可访问的url，不能携带参数。
                .build();


        Map<String, String> payInfo = null;
        try {
            payInfo = payService.getPayInfo(prepayInfo);
        } catch (WxPayException e) {
            e.printStackTrace();
        }

        return payInfo;
    }

    @Override
    public EntPayResult wxEntPay(
            String openId, Integer amount, String createIp) {

        ////////////////////////////////////////////////////////////////////////
        //生成预支付订单
        /*

        Map<String, String> data = new HashMap<String, String>();
        data.put("partner_trade_no", new Date().getTime() + "");
        data.put("openid", openId);
        data.put("check_name", "NO_CHECK");
        data.put("amount", amount.toString());
        data.put("desc", "提现");
        data.put("spbill_create_ip", spbill_create_ip);
        data.put("re_user_name", "bcn");

        data.put("mch_appid", config.getAppID());//公众账号ID
        data.put("mchid", config.getMchID());//商户号
        data.put("nonce_str", new Date().getTime() + Utility.randomString(7));//随机字符串

         */
        EntPayRequest request = EntPayRequest.newBuilder()
                .partnerTradeNo(new Date().getTime() + "")
                .openid(openId)
                .checkName("NO_CHECK")
                .amount(amount)
                .description("提现")
                .spbillCreateIp(createIp)
                .reUserName("bcn")
                .build();


        EntPayResult result = null;
        try {
            result = payService.getEntPayService().entPay(request);
        } catch (Throwable e) {
            e.printStackTrace();
        }

        return result;
    }

    @Override
    public void setMock(boolean mock) {
        mockPay = mock;
    }

    @Override
    public String wxCreateNotifyResult(String return_code, String return_msg) {

        String sXml =
                "<xml>\n" +
                "  <return_code><![CDATA[SUCCESS]]></return_code>\n" +
                "  <return_msg><![CDATA[OK]]></return_msg>\n" +
                "</xml>";
        return sXml.replace("SUCCESS", return_code).replace("OK", return_msg);
    }

    @Autowired
    AccountInfoMapper accountInfoMapper;

    @Override
    public Boolean wxTrans(Integer userId, Integer amount, String createIp) {

        AccountInfo accountInfo = accountInfoMapper.selectByPrimaryKey(userId);
        if (accountInfo == null) {
            return false;
        }

        String openId = Utility.getExtraInfo(accountInfo.getExtraInfo(), "openid");
        if (openId == null || StringUtils.isEmpty(openId)) {
            openId = WXPayUtility.getOpenIdFromExtraInfo(accountInfo.getExtraInfo());
            if (openId == null || openId.isEmpty()) {
                return false;
            }
        }

        EntPayResult r = wxEntPay(openId, amount, createIp);
        if (r == null) {
            return false;
        }
        return true;
    }

    @Override
    public Boolean wxTransV2(String openId, Integer amount, String createIp) {
        EntPayResult r = wxEntPay(openId, amount, createIp);
        System.out.println(JSONObject.toJSONString(r));
        return r != null;
    }
}
